import _ from 'lodash';
import { china, dist } from './helper';
import styles from './index.less';
import emitter from '#/utils/events';

let Map = null;
try {
  Map = AMap?.Map;
} catch (e) {
  // console.log(Map)
}

const hexagonLayer = 'hexagonLayer',
  districtLayer = 'districtLayer',
  linkLayer = 'linkLayer',
  gridLayer = 'gridLayer',
  markers = 'markers',
  disProvince = 'disProvince',
  object3DLayer = 'object3DLayer';

class visualMap3D {
  constructor() {
    this.staticProps = {};
    this.AMapAttribute = {
      resizeEnable: true, // 是否监听缩放
      mapStyle: 'amap://styles/grey', // 地图样式
      zoom: 3, // 设置地图显示的缩放级别
      viewMode: '3D',
      pitchEnable: true, // 是否允许倾斜
      pitch: 50, // 倾斜角度
      lang: 'zh_cn', // 设置地图语言类型
      zooms: [3, 18], // 地图显示的缩放级别范围3-18
      expandZoomRange: true, // 配合zooms，最大到20
      center: [104.5525, 26.0227], // 设置中国展示地图中心
      isHotspot: true, // 是否开启地图热点和标注的hover效果
      rotation: 0, // 地图顺时针旋转角度 0-360
      rotateEnable: true, // 地图是否可旋转
      dragEnable: true, // 是否可通过鼠标拖拽平移
      zoomEnable: true, // 是否可缩放
      doubleClickZoom: false, // 是否可通过双击鼠标放大地图
      keyboardEnable: true, // 是否可通过键盘控制
      scrollWheel: true, // 是否可通过滚轮控制
      skyColor: '#1a232c',
      features: ['bg', 'point', 'road', ''], // bg(地图背景) point(POI点) road(道路) building(建筑物)
    }; // 地图配置
    this.subComponentsOptions = {
      linkLayer: {
        blendMode: 'lighter',
        style: {
          // 曲率 [-1, 1] 区间
          curveness: function (data) {
            if (data.value.dis < 100) {
              return 0.07;
            } else if (data.value.dis < 300) {
              return 0.05;
            } else if (data.value.dis < 500) {
              return 0.02;
            } else if (data.value.dis < 700) {
              return 0.01;
            } else {
              return 0.005;
            }
          },
          opacity: 0.8,
          color: '#5DFBF9',
        },
      },
      hexagonLayer: {
        unit: 'meter',
        mode: 'count',
        style: {
          color: ['#0868AC', '#43A2CA', '#43A2CA', '#7BCCC4', '#BAE4BC', '#F0F9E8', '#F0F9E8'],
          radius: 1000,
          opacity: 1,
          gap: 300,
          height: [0, 11500],
        },
      },
      districtLayer: {
        mode: 'count',
        style: {
          color: ['#0c2c84', '#225ea8', '#225ea8', '#41b6c4', '#7fcdbb', '#c7e9b4', '#ffffcc'],
          height: [0, 300000],
          opacity: 0.86,
        },
      },
      gridLayer: {
        unit: 'meter',
        mode: 'count',
        style: {
          color: ['#0868AC', '#43A2CA', '#43A2CA', '#7BCCC4', '#BAE4BC', '#F0F9E8', '#F0F9E8'],
          radius: 1000,
          opacity: 1,
          gap: 300,
          height: [0, 11500],
        },
      },
    }; // 子组件配置
    this.visualMap = null; // 地图实例
    this.subComponents = []; // 子组件 hexagonLayer(热力)  linkLayer(飞线)  districtLayer(区域热力)  gridLayer(网格热力)  markers(点标记)  disProvince(行政区域)
    this.hexagonLayer = null;
    this.districtLayer = null;
    this.linkLayer = null;
    this.gridLayer = null;
    this.object3DLayer = null;
    this.markers = null;
    this.disProvince = null;
    this.makersObj = {};

    this.disProvinceColors = {};
    this.onEmitter();
  }

  // 监听数据推送
  onEmitter = () => {
    emitter.on('VisualAMapData', (res) => this.VisualAMapData(res));
  };

  // 取消监听数据推送
  offEmitter = (type = '') => {
    emitter.off(type);
  };

  // 取消所有监听数据推送
  offAllEmitter = () => {
    emitter.off('VisualAMapData', (res) => this.VisualAMapData(res));
  };
}

visualMap3D.prototype.VisualAMapData = function (res = {}) {
  if (res?.type === 'region') {
    _.map(res?.list || [], (_t) => {
      let _id = _t?.id;
      let markerSlide = this.makersObj[_id] || null,
        markerSlideData = markerSlide?.getExtData() || {};
      if (!markerSlide) return;
      if (_id === markerSlideData?.id) {
        markerSlide?.setExtData({ ...(_t || {}) });
        markerSlide?.setContent(this.setRenderMarkerContent(_t));
      }
      this.makersObj[_id] = markerSlide;
    });
  }
};

// 卸载
visualMap3D.prototype.destroy = function () {
  if (this.visualMap) {
    this.visualMap?.destroy();
  }
};

// 初始化地图
visualMap3D.prototype.onLoad = async function () {
  if (Map) {
    if (this.staticProps?.regionInfo) {
      await this.setShowRegion();
    } else {
      await this.setVisualMap();
    }
    return this.visualMap;
  }
  return null;
};

// 区域掩膜
visualMap3D.prototype.setShowRegion = function () {
  const opts = {
    subdistrict: 1,
    extensions: 'all',
    level: 'city',
  };
  //利用行政区查询获取边界构建mask路径
  //也可以直接通过经纬度构建mask路径
  let district = new AMap.DistrictSearch(opts);
  const {
    code = '',
    strokeColor,
    color,
    height,
    list = [],
    icon,
    AMapAttribute = {},
    layers = [],
    isCountry = false,
    pixel = [],
    isZoomEnb = true,
  } = this.staticProps?.regionInfo;

  district.search(dist[code]?.name || '中国', (status, result) => {
    let bounds = result?.districtList[0]?.boundaries,
      cityDistrictList = result?.districtList[0]?.districtList,
      zoom = AMapAttribute?.zoom || 10;
    let mask = [],
      meshLinePath = [];
    for (let i = 0; i < bounds.length; i += 1) {
      mask.push([bounds[i]]);
    }
    this.visualMap = new Map('visualMap', {
      ...(this.AMapAttribute || {}),
      ...(this.staticProps?.AMapAttribute || {}),
      zooms: isZoomEnb ? [zoom - 1, zoom + 2] : [zoom, zoom], // 地图显示的缩放级别范围
      zoom: zoom,
      mask: mask,
      center: dist[code]?.center || [104.5525, 26.0227],
      ...(AMapAttribute || {}),
      layers: [...layers],
    });

    _.map(list || [], (_t, _i) => {
      let marker = new AMap.Marker({
        map: this.visualMap,
        position: [_t?.lng, _t?.lat],
        offset: pixel?.length ? new AMap.Pixel(pixel[0], pixel[1]) : new AMap.Pixel(-15, -15),
        extData: { ...(_t || {}) },
        content: this.setRenderMarkerContent(_t, icon),
      });
      this.makersObj[_t?.id || _i] = marker;
    });

    if (isCountry) {
      // 创建纯文本标记
      _.map(cityDistrictList || [], (_c) => {
        let text = new AMap.Text({
          text: _c?.name || '',
          anchor: 'center', // 设置文本标记锚点
          draggable: false,
          cursor: 'pointer',
          height,
          style: {
            border: 'none',
            'background-color': 'transparent',
            'font-size': '12px',
            zoom: 0.8,
            color: '#44d0ba',
          },
          position: _c?.center,
        });

        text.setMap(this.visualMap);
      });
    }
    //添加高度面
    this.object3DLayer = new AMap.Object3DLayer({ zIndex: 20 });
    this.visualMap.add(this.object3DLayer);

    if (isCountry) {
      _.map(cityDistrictList || [], (_c) => {
        new AMap.DistrictSearch({
          subdistrict: 0, //返回下一级行政区
          extensions: 'all', //返回行政区边界坐标组等具体信息
          level: 'city', //查询行政级别为 市
        }).search(_c?.name || '', (status1, result1) => {
          let cityBounds = result1.districtList[0].boundaries,
            cityMeshLinePath = [];
          cityBounds?.forEach((_cb) => {
            _cb?.forEach((_cbn) => {
              cityMeshLinePath.push(new AMap.LngLat(_cbn.lng, _cbn.lat));
            });
          });
          let prism = new AMap.Object3D.Prism({
            path: cityBounds,
            height,
            color,
          });
          let cityMeshLine = new AMap.Object3D.MeshLine({
            path: cityMeshLinePath,
            color: '#4ce0f6',
            height,
            width: 2,
          });
          cityMeshLine.transparent = true;
          cityMeshLine.backOrFront = 'both';
          this.object3DLayer.add(cityMeshLine);
          this.object3DLayer.add(prism);
        });
      });
    } else {
      let wall = new AMap.Object3D.Wall({
        path: bounds,
        height,
        color,
      });
      this.object3DLayer.add(wall);
    }

    let lines = new AMap.Object3D.Mesh();
    let lineGeo = lines.geometry;
    //添加描边
    bounds.forEach((_b) => {
      _b?.forEach((_bn) => {
        meshLinePath.push(new AMap.LngLat(_bn.lng, _bn.lat));
        let center = this.lnglatToG20(_bn);

        // 连线
        lineGeo.vertices.push(center.x, center.y, 0);
        lineGeo.vertices.push(center.x, center.y, !isCountry ? height + -300000 : -3000000);
        lineGeo.vertexColors.push(0, 1, 1, 0.2, 0, 1, 1, 0);
      });
    });
    lines.transparent = true;
    lines.backOrFront = 'both';
    this.object3DLayer.add(lines);

    if (isCountry) {
      let meshLine = new AMap.Object3D.MeshLine({
        path: meshLinePath,
        color: strokeColor,
        height,
        width: 2,
      });
      meshLine.transparent = true;
      meshLine.backOrFront = 'both';
      this.object3DLayer.add(meshLine);
    }

    // 限制显示区域
    let showBounds = this.visualMap.getBounds();
    this.visualMap.setLimitBounds(showBounds);
  });
  if (isCountry) {
    district.search('中国', (status, result) => {
      let bounds = result?.districtList[0]?.boundaries;
      //添加高度面
      let _wall = new AMap.Object3D.Wall({
        path: bounds,
        height: -150000,
        color: '#124025',
      });
      _wall.transparent = true;
      this.object3DLayer.add(_wall);
    });
  }
};

// 创建地图
visualMap3D.prototype.setVisualMap = async function () {
  this.visualMap = await new Map('visualMap', {
    ...(this.AMapAttribute || {}),
    ...(this.staticProps?.AMapAttribute || {}),
  });

  // 添加 Object3DLayer 图层，用于添加 3DObject 对象
  this.object3DLayer = await new AMap.Object3DLayer({ zIndex: 110, opacity: 1 });
  await this.visualMap.add(this.object3DLayer);
  if (this.staticProps?.subComponents?.length) {
    this.setSubComponents();
  }
  this.setPolygonLayer();
};

// 主要用来修改初始化地图配置
visualMap3D.prototype.setDefaultVisualMapData = function (props = {}) {
  this.staticProps = { ...(props || {}) };
  // 修改地图缩放比例
  const dom = document.querySelector('#visualMap'),
    zoom = ((dom.offsetHeight * dom.offsetWidth) / (835 * 412)) * 0.26 + 3;
  this.AMapAttribute.zoom = zoom;
  this.AMapAttribute.zooms = [zoom, 18];

  this.subComponents = this.staticProps?.subComponents || [];
};

// 添加子组件
visualMap3D.prototype.setSubComponents = function () {
  if (!this.staticProps?.subComponents?.length) return;
  const list = [hexagonLayer, districtLayer, linkLayer, gridLayer];
  _.map(this.staticProps?.subComponents || [], (_s) => {
    switch (_s?.name) {
      case hexagonLayer:
        this.setHexagonLayer(_s);
        break;
      case districtLayer:
        this.setDistrictLayer(_s);
        break;
      case linkLayer:
        this.setLinkLayer(_s);
        break;
      case gridLayer:
        this.setGridLayer(_s);
        break;
      case object3DLayer:
        this.setObject3DLayer(_s);
        break;
      case markers:
        this.setMarkers(_s);
        break;
      case disProvince:
        this.setDisProvince(_s);
        break;
      default:
        break;
    }
    if (list.includes(_s?.name)) {
      this[_s?.name]?.setOptions({
        ...(this.subComponentsOptions[_s?.name] || {}),
        ...(_s?.options || {}),
      });
      this[_s?.name]?.render();
    }
  });
};

// 行政区域
visualMap3D.prototype.setDisProvince = function (slide = {}) {
  const { dep = 2, code = 110000 } = slide;

  this.disProvince && this.disProvince.setMap(null);
  this.disProvince = new AMap.DistrictLayer.Province({
    zIndex: 12,
    adcode: [code],
    depth: dep,
    styles: {
      fill: (properties) => {
        // properties为可用于做样式映射的字段，包含
        // NAME_CHN:中文名称
        // adcode_pro
        // adcode_cit
        // adcode
        return this.getColorByAdcode(properties.adcode);
      },
      'province-stroke': 'cornflowerblue',
      'city-stroke': 'white', // 中国地级市边界
      'county-stroke': 'rgba(255,255,255,0.5)', // 中国区县边界
    },
  });

  this.disProvince.setMap(this.visualMap);
};
// 颜色辅助方法
visualMap3D.prototype.getColorByAdcode = function (code = '') {
  if (!this.disProvinceColors[code]) {
    let gb = Math.random() * 155 + 50;
    this.disProvinceColors[code] = 'rgb(' + gb + ',' + gb + ',255)';
  }

  return this.disProvinceColors[code];
};

// 设置点标记
visualMap3D.prototype.setRenderMarkerContent = function (slide = {}) {
  return this.staticProps?.renderMarkerContent
    ? this.staticProps?.renderMarkerContent(slide)
    : this.renderMarkerContent(slide);
};

// 自定义点标记
visualMap3D.prototype.setMarkers = function (slide = {}) {
  this.markers = new AMap.LabelsLayer({
    zIndex: 1000,
    collision: false,
    animation: true,
  });

  _.map(slide.data || [], (_d) => {
    let lng = _d?.lng || '0',
      lat = _d?.lat || '0';
    let lnglat = [lng, lat];

    let marker = new AMap.Marker({
      map: this.visualMap,
      position: lnglat,
      extData: {
        lnglat,
        curData: _d || {}, // 当前数据
      },
      content: this.setRenderMarkerContent(_d),
    });

    this.markers.add(marker);
  });
};
visualMap3D.prototype.renderMarkerContent = function (slide = {}, icon) {
  let domStr = `<div class="${styles.marker_container}"><span class="${
    styles.marker_container_inner
  }">${slide?.value || ''}</span><img src=${icon} class="${styles.marker_container_icon}"></div>`;
  return domStr;
};

// 蜂窝热力
visualMap3D.prototype.setHexagonLayer = function (slide = {}) {
  this.hexagonLayer = new Loca.HexagonLayer({
    map: this.visualMap,
    eventSupport: true,
  });
  this.hexagonLayer.setData(slide?.data || '', {
    lnglat: function (obj) {
      let val = obj.value;
      return [val.lng, val.lat];
    },
    value: 'count',
    type: 'tsv',
  });
};

// 区域热力
visualMap3D.prototype.setDistrictLayer = function (slide = {}) {
  this.districtLayer = new Loca.DistrictLayer({
    map: this.visualMap,
  });
  this.districtLayer.setData(slide?.data || '', {
    type: 'csv',
    lnglat: '经纬度',
    value: '知名景区数量',
  });
};

// 网格热力
visualMap3D.prototype.setGridLayer = function (slide = {}) {
  this.gridLayer = new Loca.GridLayer({
    map: this.visualMap,
  });
  this.gridLayer.setData(slide?.data || '', {
    lnglat: function (obj) {
      let val = obj.value;
      return [val.lng, val.lat];
    },
    value: 'count',
    type: 'tsv',
  });
};

// 飞线
visualMap3D.prototype.setLinkLayer = function (slide = {}) {
  this.linkLayer = new Loca.LinkLayer({
    map: this.visualMap,
    fitView: false,
  });
  this.linkLayer.setData(slide?.data?.slice(0, 500) || '', {
    lnglat: 'lnglat',
  });
};

// 散点
visualMap3D.prototype.lnglatToG20 = function (lnglat) {
  let res = this.visualMap.lngLatToGeodeticCoord(lnglat);
  res.x = AMap.Util.format(res.x, 3);
  res.y = AMap.Util.format(res.y, 3);
  return res;
};
visualMap3D.prototype.setObject3DLayer = function () {
  let lines = new AMap.Object3D.Line();
  let lineGeo = lines.geometry;
  new AMap.DistrictSearch({
    subdistrict: 1, //返回下一级行政区
    extensions: 'base',
  }).search('中国', (status, result) => {
    let provinces = result?.districtList[0]?.districtList || [];
    let points3D = new AMap.Object3D.RoundPoints();
    points3D.transparent = true;
    let pointsGeo = points3D.geometry;
    for (let p = 0; p < provinces.length; p += 1) {
      let center = this.lnglatToG20(provinces[p].center);
      let size = Math.max(10, Math.round(Math.random() * 40));
      let height = -size * 100000;

      // 连线
      lineGeo.vertices.push(center.x, center.y, 0);
      lineGeo.vertexColors.push(0, 1, 1, 1);
      lineGeo.vertices.push(center.x, center.y, height);
      lineGeo.vertexColors.push(0, 1, 1, 1);

      pointsGeo.vertices.push(center.x, center.y, 0); // 尾部小点
      pointsGeo.pointSizes.push(5);
      pointsGeo.vertexColors.push(0, 0, 1, 1);

      pointsGeo.vertices.push(center.x, center.y, height); // 空中点
      pointsGeo.pointSizes.push(size);
      pointsGeo.vertexColors.push(p * 0.029, p * 0.015, p * 0.01, 1);
    }

    points3D.borderColor = [0.4, 0.8, 1, 1];
    points3D.borderWeight = 3;
    this.object3DLayer.add(lines);
    this.object3DLayer.add(points3D);
  });
};

// 行政区边界
visualMap3D.prototype.setPolygonLayer = function () {
  this.polygonLayer = new Loca.PolygonLayer({
    map: this.visualMap,
  });
  this.polygonLayer.setData(china || [], {
    lnglat: 'center',
  });
};

visualMap3D.getInstance = (function () {
  let instance;
  return function () {
    instance = instance ? instance : new visualMap3D();
    return instance;
  };
})();

export const visualMaps3D = visualMap3D.getInstance();
